package com.tecnoin.tintconta.core.persist;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import com.tecnoin.tintconta.core.FiltroLibroDiario;
import com.tecnoin.tintconta.core.entities.Clasificacion;
import com.tecnoin.tintconta.core.entities.Cuenta;
import com.tecnoin.tintconta.core.entities.Ejercicio;
import com.tecnoin.tintconta.core.entities.Empresa;
import com.tecnoin.tintconta.core.entities.ParametroEmpresa;
import com.tecnoin.tintconta.core.entities.Partida;
import com.tecnoin.tintconta.core.entities.Rubro;

public class TINTContabilidadPersist {
	  /** Uses JNDI and Datasource (preferred style).   */
	  public static Connection getJNDIConnection()
	  {
	    String DATASOURCE_CONTEXT = "jdbc/tintContabilidad";
	    Connection result = null;
	    try 
	    {
		      Context initialContext = new InitialContext();
		      if ( initialContext == null)
		      {
		        log("JNDI problem. Cannot get InitialContext.");
		      }
		      DataSource datasource = (DataSource)initialContext.lookup(DATASOURCE_CONTEXT);
		      if (datasource != null) 
		      {
		        result = datasource.getConnection();
		      }
		      else 
		      {
		        log("Failed to lookup datasource.");
		      }
	    }
	    catch ( NamingException ex ) 
	    {
	      log("Cannot get connection: " + ex);
	    }
	    catch(SQLException ex)
	    {
	      log("Cannot get connection: " + ex);
	    }
	    return result;
	  }
	  
	  public static void closeQuietly(Connection c, Statement stm, ResultSet rs)
	  {
		  if(rs!=null)
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		  if(stm!=null)
			try {
				stm.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		  if(c!=null)
			try {
				c.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
	  }
	  
	  private static void log(String line)
	  {
		  System.out.println(line);
	  }

	public static Empresa seleccionarEmpresa(int id) 
	{
		Empresa emp = new Empresa();
		Connection c = getJNDIConnection();
		if(c!=null)
		{
			Statement stm = null;
			ResultSet rs  = null;
			try 
			{
				stm = c.createStatement();
				rs = stm.executeQuery("select nombre, nit, nrc, giro1, giro2, giro3 from empresa where id = " + id);
				if(rs.next())
				{
					emp.setId(id);
					emp.setNombre(rs.getString(1));
					emp.setNit(rs.getString(2));
					emp.setNrc(rs.getString(3));
					emp.setGiro1(rs.getString(4));
					emp.setGiro2(rs.getString(5));
					emp.setGiro3(rs.getString(6));
				}
				rs.close();
				rs = null;
				Map<String, ParametroEmpresa> parametros = parametrosEmpresa(emp, stm);
				Map<String, Ejercicio> ejercicios = ejercicios(emp, stm);
				List<Rubro> rubros = rubros(emp, stm);
				Map<String, Clasificacion> clasificaciones = clasificaciones(emp, stm);
				emp.setEjercicios(ejercicios);
				emp.setParametros(parametros);
				emp.setRubros(rubros);
				emp.setClasificaciones(clasificaciones);
			} 
			catch (SQLException e) 
			{
				e.printStackTrace();
			}
			finally
			{
				closeQuietly(c, stm, rs);
			}
			return emp;
		}
		return null;
	}
	
	public static Map<String, Clasificacion> clasificaciones(Empresa emp, Statement stm)
	{
		Map<String, Clasificacion> clasificaciones = new HashMap<String, Clasificacion>();
		String sql = "select id, codigo, nombre from clasificacion where idempresa = " + emp.getId();
		ResultSet rs = null;
		try 
		{
			rs = stm.executeQuery(sql);
			while(rs.next())
			{
				Clasificacion c = new Clasificacion();
				c.setId(rs.getInt(1));
				c.setCodigo(rs.getString(2));
				c.setNombre(rs.getString(3));
				c.setEmpresa(emp);
				clasificaciones.put(c.getCodigo(), c);
			}
			rs.close();
			rs = null;
			agregarDetalleCuentas(clasificaciones, stm);
		} 
		catch (SQLException e) 
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return clasificaciones;
	}
	
	private static void agregarDetalleCuentas(Map<String, Clasificacion> clasificaciones, Statement stm) 
	{
		if(clasificaciones.isEmpty())
			return;
		Clasificacion clTest = clasificaciones.values().iterator().next();
		Empresa empresa = clTest.getEmpresa();
		int idEmpresa = empresa.getId();
		String sql = "select cta.numero, cls.codigo " +
					 " from cuenta cta, clasificacion cls, clasificacionCuenta x, rubro rub " +
					 " where cls.idEmpresa = " + idEmpresa +
					 " and cta.idRubro = rub.id  " +
					 " and rub.idempresa = " + idEmpresa +
					 " and cls.id = x.idClasificacion " + 
					 " and cta.id = x.idCuenta";
		ResultSet rs = null;
		try 
		{
			rs = stm.executeQuery(sql);
			while(rs.next())
			{
				String cuenta = rs.getString(1);
				String clasificacion = rs.getString(2);
				Cuenta cta = empresa.getCuentas().get(cuenta);
				Clasificacion cls = clasificaciones.get(clasificacion);
				if(cta!=null && cls!=null)
				{
					cta.getClasificaciones().add(cls);
					cls.getCuentas().add(cta);
				}
			}
		} 
		catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static Map<String, ParametroEmpresa> parametrosEmpresa(Empresa empresa, Statement stm)
	{
		Map<String, ParametroEmpresa> m = new HashMap<String, ParametroEmpresa>();
		Statement stmUse = stm;
		String sql = "select id, llave, valor, descripcion from parametroEMpresa where idEmpresa = " + empresa.getId();
		ResultSet rs = null;
		try {
			rs = stm.executeQuery(sql);
			while(rs.next())
			{
				ParametroEmpresa p = new ParametroEmpresa();
				p.setId(rs.getInt(1));
				p.setLlave(rs.getString(2));
				p.setValor(rs.getString(3));
				p.setDescripcion(rs.getString(4));
				p.setEmpresa(empresa);
				m.put(p.getLlave(), p);
			}
			rs.close();
			rs = null;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return m;
	}
	
	public static Map<String, Ejercicio> ejercicios(Empresa emp, Statement stm)
	{
		Map<String, Ejercicio> ejerciciox = new HashMap<String, Ejercicio>();
		String sql = "select id, codigo, nombre, inicio, fin, estado from ejercicio where idEmpresa = " + emp.getId();
		ResultSet rs = null;
		try 
		{
			rs = stm.executeQuery(sql);
			while(rs.next())
			{
				Ejercicio e = new Ejercicio();
				e.setEmpresa(emp);
				e.setId(rs.getInt(1));
				e.setCodigo(rs.getString(2));
				e.setNombre(rs.getString(3));
				e.setInicio(rs.getString(4));
				e.setFin(rs.getString(5));
				e.setEstado(rs.getString(6));
				if(e.getEstado()!=null && e.getEstado().trim().equalsIgnoreCase("A"))
					emp.setEjercicioActivo(e);
				ejerciciox.put(e.getCodigo(), e);
			}
			rs.close();
			rs = null;
		} 
		catch (SQLException e) 
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return ejerciciox;
	}
	/**
	 * Lista de Rubros
	 * @param emp
	 * @param stm
	 * @return
	 */
	public static List<Rubro> rubros(Empresa emp, Statement stm)
	{
		List<Rubro> l = new ArrayList<Rubro>();
		String sql = "select id, codigo, nombre from rubro where idEmpresa = " + emp.getId();
		ResultSet rs = null;
		try 
		{
			rs = stm.executeQuery(sql);
			while(rs.next())
			{
				Rubro r = new Rubro();
				r.setId(rs.getInt(1));
				r.setCodigo(rs.getString(2));
				r.setNombre(rs.getString(3));
				r.setEmpresa(emp);
				l.add(r);
			}
			rs.close();
			rs = null;
		} 
		catch (SQLException e) 
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Iterator<Rubro> i = l.iterator();
		while(i.hasNext())
		{
			Rubro r = i.next();
			adicionarCuentas(r, stm);
		}
		return l;
	}

	/**
	 * Adiciona las cuentas a un rubro en especifico
	 * @param r
	 * @param stm
	 */
	private static void adicionarCuentas(Rubro r, Statement stm) 
	{
		Empresa emp = r.getEmpresa();
		List<Cuenta> cuentas = new ArrayList<Cuenta>();
		Map<String, Cuenta> cuentasMap = emp.getCuentas();
		Map<Long, Cuenta> cuentasMapIDEmp = emp.getCuentasPorID();
		Map<Integer, Cuenta> cuentasMapID = new HashMap<Integer, Cuenta>();
		String sql = "select id, idCuentaPadre, numero, nombre, saldo, estado from cuenta where idRubro = " + r.getId() ;
		ResultSet rs = null;
		try 
		{
			rs = stm.executeQuery(sql);
			while(rs.next())
			{
				Cuenta c = new Cuenta();
				c.setId(rs.getInt(1)); 
				c.setIdCuentaPadre(rs.getString(2));
				c.setNumero(rs.getString(3));
				c.setNombre(rs.getString(4));
				c.setSaldo(rs.getDouble(5));
				c.setEstado(rs.getString(6));
				c.setRubro(r);
				cuentas.add(c);
				cuentasMap.put(c.getNumero(), c);
				cuentasMapID.put(new Integer(c.getId()), c);
				cuentasMapIDEmp.put(new Long(c.getId()), c);
			}
		} 
		catch (SQLException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Iterator<Cuenta> i = cuentas.iterator();
		while(i.hasNext())
		{
			Cuenta ch = i.next();
			if(ch.getIdCuentaPadre()!=null && !ch.getIdCuentaPadre().trim().equalsIgnoreCase("null"))
			{
				Cuenta cuentaPadre = cuentasMapID.get(new Long(ch.getIdCuentaPadre()));
				ch.setCuentaPadre( cuentaPadre );
				cuentaPadre.getCuentasDependientes().put(ch.getNumero(), ch);
			}	
		}
		r.setCuentas(cuentas);
	}

	public static void filtrarPartidas(List<Partida> libroDiarioFiltrado2, FiltroLibroDiario filtroPartidas, Empresa empresa) 
	{
		String sqlBase = "select id, idclasificacion, total, fechaProceso, comentario, estado, idejercicio  from libroDiarioView";
		Map<Long, Partida> partidasTemp = new HashMap<Long, Partida>();
		String ands    = andsSegunFiltro(filtroPartidas);
		Connection cnx = getJNDIConnection();
		Statement stm = null;
		ResultSet rs = null;
		try 
		{
			stm = cnx.createStatement();
			rs  = stm.executeQuery(sqlBase + " " + ands);
			while(rs.next())
			{
				long id = rs.getLong(1);
				String idClasificacion = rs.getString(2);
				Partida p = partidasTemp.get(id);	
				if(p==null)
				{
					p = new Partida();
					p.setId(id);
					p.setTotal(rs.getDouble(3));
					p.setFechaProceso(rs.getString(4));
					p.setComentario(rs.getString(5));
					p.setEstado(rs.getString(6));
					Ejercicio ejercicio = empresa.getEjercicios().get(rs.getObject(7));
					p.setEjercicio(ejercicio);
					partidasTemp.put(id, p);
					libroDiarioFiltrado2.add(p);
				}
				//Asociar clasificacion de todas maneras
				if(idClasificacion!=null)
				{
					Long idClasificacionL = new Long(idClasificacion);
					Clasificacion clasificacion = empresa.getClasificaciones().get(idClasificacionL);
					if(clasificacion!=null)
						p.getClasificaciones().put(idClasificacionL, clasificacion);
				}
			}
		} 
		catch (SQLException e) 
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally
		{
			closeQuietly(cnx, stm, rs);
		}
		partidasTemp.clear();
		partidasTemp = null;
	}

	public static void mainTestSQLLibroDiario()
	{
		List<Partida> l = new ArrayList<Partida>();
		List<Clasificacion> lc = new ArrayList<Clasificacion>();
		
		Clasificacion cl1 = new Clasificacion(),
					  cl2 = new Clasificacion(),
					  cl3 = new Clasificacion();
		cl1.setId(11);
		cl2.setId(22);
		cl3.setId(33);
		lc.add(cl1);
		lc.add(cl2);
		lc.add(cl3);
		Ejercicio e = new Ejercicio();
		e.setId(2555);
		
		FiltroLibroDiario f = new FiltroLibroDiario();
		f.setFechaInicio("2011-12-01");
		f.setFechaFinal("2011-12-31");
		f.setClasificaciones(lc);
		f.setEjercicio(e);
		//f.setEstadoPartida("A");
		String sqlAnds = andsSegunFiltro(f);
		System.out.println(sqlAnds);
	}
	
	public static void main(String[] a)
	{
		mainTestSQLLibroDiario();
		
	}
	
	private static String andsSegunFiltro(FiltroLibroDiario filtroPartidas) 
	{
		Ejercicio ejEspecifico = filtroPartidas.getEjercicio();
		String fechaInicio = filtroPartidas.getFechaInicio(), fechaFinal = filtroPartidas.getFechaFinal();
		List<Clasificacion> clasificaciones = filtroPartidas.getClasificaciones();
		String estado = filtroPartidas.getEstadoPartida();
		String retVal = " where ";
		List<String> condiciones = new ArrayList<String>();
		boolean evalEjercicio = ejEspecifico != null,
				evalFechas    = fechaInicio!=null && fechaFinal!=null,
				evalClas	  = clasificaciones!=null && !clasificaciones.isEmpty(),
				evalEstado    = estado!=null;
		if(filtroPartidas.getIdPartida()>0)
			return " id = " + filtroPartidas.getIdPartida();
		if(evalEjercicio)
			condiciones.add(" idEjercicio = " + ejEspecifico.getId());
		if(evalFechas)
			condiciones.add("  ( fechaProceso between date('" + fechaInicio + "') and date('" + fechaFinal + "') ) ");
		if(evalClas)
			condiciones.add(" " + clasificacionesSQL(clasificaciones));
		if(evalEstado)
			condiciones.add( " estado = '" + estado + "' ");
		int size = condiciones.size(), x=0;
		for(String s: condiciones)
		{
			retVal += s;
			x++;
			if(x!=size)
				retVal += " and ";
		}
		return retVal;
	}

	private static String clasificacionesSQL(List<Clasificacion> clasificaciones)
	{
		String retVal = " idClasificacion in (";
		int x = clasificaciones.size(), c = 0;
		for(Clasificacion cls: clasificaciones)
		{
			retVal += cls.getId();
			c++;
			if(c!=x)
				retVal+=",";
		}
		retVal += ")";
		return retVal;
	}
}